<script setup lang="ts">
import { ref, provide, inject, onMounted, onUnmounted, nextTick, watch } from 'vue'
import { h } from 'vue'
import { NIcon } from 'naive-ui' //

type MenuKey =
  | 'control_center'
  | 'survey'
  | 'available_attack_resources'
  | 'dns_dashboard'
  | 'topology_designer'
  | 'attack_effect_monitor'
  | 'ip_geo_map'

const props = defineProps<{
  activeKey: MenuKey
}>()

const emit = defineEmits<{
  (e: 'update:activeKey', key: MenuKey): void
  (e: 'navigate', key: MenuKey): void
}>()

// 菜单项类型定义
type MenuItem = {
  key: MenuKey
  label: string
  children?: Array<{ key: MenuKey; label: string }>
}

const menuItems: MenuItem[] = [
  { key: 'control_center', label: '系统控制总览' },
  { key: 'dns_dashboard', label: '测试节点监控' },
  {
    key: 'survey',
    label: '攻击资源测绘',
    children: [
      { key: 'survey', label: '任务发布' },
      { key: 'available_attack_resources', label: '任务详情' },
      { key: 'ip_geo_map', label: '资源分布' }
    ]
  },
  { key: 'topology_designer', label: '链型构建优化' },
  { key: 'attack_effect_monitor', label: '打击效果评估' }
]

// 系统名称
const systemName = 'DNS自激聚能断网攻击验证系统'

// 刷新功能
function handleRefresh() {
  window.location.reload()
}

// 搜索功能相关状态
const showSearchBox = ref(false)
const searchQuery = ref('')
const currentMatchIndex = ref(0)
const totalMatches = ref(0)
const searchHighlights: HTMLElement[] = []
let topologySearchInterface: any = null

// 打开搜索框
function handleSearch() {
  showSearchBox.value = !showSearchBox.value
  if (showSearchBox.value) {
    nextTick(() => {
      const input = document.querySelector('.search-input') as HTMLInputElement
      if (input) {
        input.focus()
      }
    })
  } else {
    clearSearch()
  }
}

// 清除搜索高亮
function clearSearch() {
  searchHighlights.forEach(el => {
    if (el.parentNode) {
      const parent = el.parentNode
      parent.replaceChild(document.createTextNode(el.textContent || ''), el)
      parent.normalize()
    }
  })
  searchHighlights.length = 0
  totalMatches.value = 0
  currentMatchIndex.value = 0
}

// 执行搜索
function performSearch() {
  const query = searchQuery.value.trim()
  
  if (!query) {
    clearSearch()
    return
  }

  clearSearch()

  console.log('[系统搜索] 搜索关键词:', query, '当前页面:', props.activeKey)
  
  // 如果当前页面是 TopologyDesigner，先尝试搜索节点列表（包括未渲染的节点）
  topologySearchInterface = null
  if (props.activeKey === 'topology_designer') {
    const topologySearch = (window as any).topologyDesignerSearch
    console.log('[系统搜索] TopologyDesigner 搜索接口:', topologySearch)
    if (topologySearch && typeof topologySearch === 'function') {
      const nodeSearchResult = topologySearch(query)
      console.log('[系统搜索] 节点搜索结果:', nodeSearchResult)
      topologySearchInterface = nodeSearchResult
      if (nodeSearchResult.found) {
        // 滚动到第一个匹配的节点
        nodeSearchResult.scrollToFirst()
        // 将节点匹配数计入总匹配数
        // 注意：节点搜索的匹配数会与 DOM 搜索的匹配数合并
      }
    }
  }
  
  const pageContent = document.querySelector('.page-content')
  console.log('[系统搜索] page-content 元素:', pageContent)
  if (!pageContent) {
    // 如果没有找到 page-content，仍然检查节点搜索
    const nodeMatchCount = topologySearchInterface?.matchCount || 0
    totalMatches.value = nodeMatchCount
    currentMatchIndex.value = 0
    console.log('[系统搜索] 没有找到 page-content，节点匹配数:', nodeMatchCount)
    return
  }

  const walker = document.createTreeWalker(
    pageContent,
    NodeFilter.SHOW_TEXT,
    {
      acceptNode: node => {
        if (node.parentElement?.classList.contains('search-highlight')) {
          return NodeFilter.FILTER_REJECT
        }
        return NodeFilter.FILTER_ACCEPT
      }
    }
  )

  const textNodes: Text[] = []
  let node: Node | null
  // eslint-disable-next-line no-cond-assign
  while ((node = walker.nextNode())) {
    if (node.textContent && node.textContent.includes(query)) {
      textNodes.push(node as Text)
    }
  }

  // 即使没有 DOM 匹配，也要检查是否有节点匹配
  if (textNodes.length === 0) {
    // 如果有节点匹配，仍然显示匹配数
    const nodeMatchCount = topologySearchInterface?.matchCount || 0
    totalMatches.value = nodeMatchCount
    currentMatchIndex.value = 0
    // 如果没有节点匹配也没有 DOM 匹配，totalMatches 已经是 0，直接返回
    if (nodeMatchCount === 0) {
      return
    }
    // 如果有节点匹配，不需要继续执行 DOM 搜索，直接返回
    return
  }

  let matchCount = 0
  textNodes.forEach(textNode => {
    const text = textNode.textContent || ''
    const regex = new RegExp(escapeRegExp(query), 'gi')
    const matches = [...text.matchAll(regex)]

    if (matches.length === 0) return

    const parent = textNode.parentNode
    if (!parent) return

    const fragment = document.createDocumentFragment()
    let lastIndex = 0

    matches.forEach(match => {
      if (match.index === undefined) return

      if (match.index > lastIndex) {
        fragment.appendChild(
          document.createTextNode(text.substring(lastIndex, match.index))
        )
      }

      const highlight = document.createElement('mark')
      highlight.className = 'search-highlight'
      highlight.textContent = match[0]
      highlight.setAttribute('data-match-index', matchCount.toString())
      searchHighlights.push(highlight)
      fragment.appendChild(highlight)
      matchCount++

      lastIndex = match.index + match[0].length
    })

    if (lastIndex < text.length) {
      fragment.appendChild(
        document.createTextNode(text.substring(lastIndex))
      )
    }

    parent.replaceChild(fragment, textNode)
  })

  // 合并节点搜索和 DOM 搜索的匹配数
  const nodeMatchCount = topologySearchInterface?.matchCount || 0
  totalMatches.value = matchCount + nodeMatchCount
  currentMatchIndex.value = 0
  
  console.log('[系统搜索] DOM 匹配数:', matchCount, '节点匹配数:', nodeMatchCount, '总匹配数:', totalMatches.value)

  // 如果有匹配项，优先滚动到节点匹配（如果存在），否则滚动到 DOM 匹配
  if (totalMatches.value > 0) {
    if (nodeMatchCount > 0) {
      // 节点匹配优先，已经在 searchNodesInList 中滚动
      console.log('[系统搜索] 滚动到节点匹配')
    } else if (matchCount > 0) {
      console.log('[系统搜索] 滚动到 DOM 匹配')
      scrollToMatch(0)
    }
  } else {
    console.log('[系统搜索] 没有找到任何匹配项')
  }
}

// 转义正则表达式特殊字符
function escapeRegExp(str: string): string {
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}

// 滚动到指定索引的匹配项
function scrollToMatch(index: number) {
  // 如果当前页面是 TopologyDesigner 且有节点匹配，优先使用节点搜索导航
  if (props.activeKey === 'topology_designer' && topologySearchInterface) {
    const nodeMatchCount = topologySearchInterface.matchCount || 0
    if (nodeMatchCount > 0) {
      // 节点搜索的匹配项优先
      if (index < nodeMatchCount) {
        topologySearchInterface.scrollToIndex(index)
        currentMatchIndex.value = index
        return
      } else {
        // 超出节点匹配数，减去节点匹配数后查找 DOM 匹配
        index = index - nodeMatchCount
      }
    }
  }
  
  const highlights = document.querySelectorAll('.search-highlight')
  if (highlights.length === 0) return

  const targetIndex = Math.max(0, Math.min(index, highlights.length - 1))
  const target = highlights[targetIndex] as HTMLElement

  if (target) {
    target.scrollIntoView({ behavior: 'smooth', block: 'center' })
    highlights.forEach((el, i) => {
      if (i === targetIndex) {
        el.classList.add('current-match')
      } else {
        el.classList.remove('current-match')
      }
    })
    currentMatchIndex.value = targetIndex
  }
}

// 下一个 / 上一个匹配
function nextMatch() {
  if (totalMatches.value === 0) return
  
  // 如果当前页面是 TopologyDesigner 且有节点匹配，优先使用节点搜索导航
  if (props.activeKey === 'topology_designer' && topologySearchInterface) {
    const nodeMatchCount = topologySearchInterface.matchCount || 0
    if (nodeMatchCount > 0 && currentMatchIndex.value < nodeMatchCount) {
      // 当前在节点匹配范围内，导航到下一个节点匹配
      topologySearchInterface.scrollToNext()
      currentMatchIndex.value = (currentMatchIndex.value + 1) % totalMatches.value
      return
    }
  }
  
  const nextIndex = (currentMatchIndex.value + 1) % totalMatches.value
  scrollToMatch(nextIndex)
}

function prevMatch() {
  if (totalMatches.value === 0) return
  
  // 如果当前页面是 TopologyDesigner 且有节点匹配，优先使用节点搜索导航
  if (props.activeKey === 'topology_designer' && topologySearchInterface) {
    const nodeMatchCount = topologySearchInterface.matchCount || 0
    if (nodeMatchCount > 0 && currentMatchIndex.value <= nodeMatchCount) {
      // 当前在节点匹配范围内，导航到上一个节点匹配
      topologySearchInterface.scrollToPrev()
      const total = totalMatches.value
      currentMatchIndex.value = (currentMatchIndex.value - 1 + total) % total
      return
    }
  }
  
  const prevIndex =
    (currentMatchIndex.value - 1 + totalMatches.value) % totalMatches.value
  scrollToMatch(prevIndex)
}

// 监听搜索关键词变化，实时搜索
watch(searchQuery, () => {
  // 使用 nextTick 确保 DOM 更新后再搜索
  nextTick(() => {
    performSearch()
  })
}, { immediate: false })

// 监听页面切换，如果搜索框有内容，重新搜索
watch(() => props.activeKey, () => {
  // 页面切换时，如果搜索框有内容，等待 DOM 更新后重新搜索
  if (searchQuery.value.trim()) {
    // 等待页面内容加载完成
    setTimeout(() => {
      nextTick(() => {
        performSearch()
      })
    }, 100)
  }
})

// 键盘快捷键支持
function handleKeyDown(event: KeyboardEvent) {
  if ((event.ctrlKey || event.metaKey) && event.key === 'f') {
    event.preventDefault()
    if (!showSearchBox.value) {
      handleSearch()
    }
  }

  if (event.key === 'Escape' && showSearchBox.value) {
    showSearchBox.value = false
    clearSearch()
  }

  if (
    showSearchBox.value &&
    event.target instanceof HTMLElement &&
    event.target.classList.contains('search-input')
  ) {
    if (event.key === 'Enter') {
      event.preventDefault()
      if (event.shiftKey) {
        prevMatch()
      } else {
        nextMatch()
      }
    }
  }
}

// 监听节点搜索滚动事件，当节点被渲染后重新执行 DOM 搜索来高亮文本
function handleNodeSearchScrolled(event: CustomEvent) {
  const query = event.detail?.query
  if (query && searchQuery.value.trim()) {
    // 重新执行 DOM 搜索，高亮新渲染的节点中的匹配文本
    // 不清除现有的高亮，只搜索新渲染的内容
    const pageContent = document.querySelector('.page-content')
    if (!pageContent) return
    
    // 只搜索节点列表区域，避免重复高亮其他内容
    const nodeListArea = pageContent.querySelector('.td-sidebar')
    if (!nodeListArea) return
    
    const walker = document.createTreeWalker(
      nodeListArea,
      NodeFilter.SHOW_TEXT,
      {
        acceptNode: node => {
          // 跳过已经高亮的文本节点
          if (node.parentElement?.classList.contains('search-highlight')) {
            return NodeFilter.FILTER_REJECT
          }
          // 只搜索节点项内的文本
          if (node.parentElement?.closest('.node-item')) {
            return NodeFilter.FILTER_ACCEPT
          }
          return NodeFilter.FILTER_REJECT
        }
      }
    )
    
    const textNodes: Text[] = []
    let node: Node | null
    // eslint-disable-next-line no-cond-assign
    while ((node = walker.nextNode())) {
      if (node.textContent && node.textContent.toLowerCase().includes(query.toLowerCase())) {
        textNodes.push(node as Text)
      }
    }
    
    // 高亮匹配的文本节点
    textNodes.forEach(textNode => {
      const text = textNode.textContent || ''
      const regex = new RegExp(escapeRegExp(query), 'gi')
      const matches = [...text.matchAll(regex)]
      
      if (matches.length === 0) return
      
      const parent = textNode.parentNode
      if (!parent) return
      
      const fragment = document.createDocumentFragment()
      let lastIndex = 0
      
      matches.forEach(match => {
        if (match.index === undefined) return
        
        if (match.index > lastIndex) {
          fragment.appendChild(
            document.createTextNode(text.substring(lastIndex, match.index))
          )
        }
        
        const highlight = document.createElement('mark')
        highlight.className = 'search-highlight'
        highlight.textContent = match[0]
        highlight.setAttribute('data-match-index', searchHighlights.length.toString())
        searchHighlights.push(highlight)
        fragment.appendChild(highlight)
        
        lastIndex = match.index + match[0].length
      })
      
      if (lastIndex < text.length) {
        fragment.appendChild(
          document.createTextNode(text.substring(lastIndex))
        )
      }
      
      parent.replaceChild(fragment, textNode)
    })
    
    // 更新总匹配数（只更新 DOM 匹配数，节点匹配数不变）
    // 注意：这里不需要更新 totalMatches，因为节点匹配数已经包含在总匹配数中了
    // DOM 搜索会在 performSearch 中统一处理，这里只是补充高亮新渲染的节点
  }
}

onMounted(() => {
  window.addEventListener('keydown', handleKeyDown)
  window.addEventListener('node-search-scrolled', handleNodeSearchScrolled as EventListener)
})

onUnmounted(() => {
  window.removeEventListener('keydown', handleKeyDown)
  window.removeEventListener('node-search-scrolled', handleNodeSearchScrolled as EventListener)
  clearSearch()
})

// 导航处理
function handleNavigation(key: MenuKey) {
  if (key !== props.activeKey) {
    // 不清除搜索内容，保留搜索关键词，让 watch 监听器处理重新搜索
    emit('update:activeKey', key)
    emit('navigate', key)
  }
}

// 监听导航事件（用于ControlCenter等组件通过CustomEvent导航）
function handleNavigate(event: CustomEvent) {
  const pageKey = event.detail?.page
  const validKeys: MenuKey[] = [
    'control_center',
    'survey',
    'available_attack_resources',
    'dns_dashboard',
    'topology_designer',
    'attack_effect_monitor',
    'ip_geo_map'
  ]
  if (pageKey && validKeys.includes(pageKey as MenuKey)) {
    handleNavigation(pageKey as MenuKey)
  }
}

onMounted(() => {
  window.addEventListener('navigate', handleNavigate as EventListener)
})

onUnmounted(() => {
  window.removeEventListener('navigate', handleNavigate as EventListener)
})

// 注入父组件的导航方法（如果存在），然后提供给子组件
const parentNavigateToAttackEffect = inject<(ip: string) => void>(
  'navigateToAttackEffect'
)
provide(
  'navigateToAttackEffect',
  parentNavigateToAttackEffect ||
    (() => {
      console.warn('navigateToAttackEffect 未找到父级提供者')
    })
)
</script>

<template>
  <div class="app-layout">
    <!-- 顶部系统条 -->
    <header class="system-header">
      <div class="system-header-content">
        <div class="system-name">
          {{ systemName }}
        </div>
        <div class="system-header-right">
          <button class="header-icon-btn" @click="handleRefresh" title="刷新">
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="18"
              height="18"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
            >
              <polyline points="23 4 23 10 17 10" />
              <polyline points="1 20 1 14 7 14" />
              <path
                d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"
              />
            </svg>
          </button>

          <div class="search-container">
            <button
              class="header-icon-btn"
              @click="handleSearch"
              title="搜索 (Ctrl+F)"
              :class="{ active: showSearchBox }"
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                width="18"
                height="18"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
              >
                <circle cx="11" cy="11" r="8" />
                <path d="m21 21-4.35-4.35" />
              </svg>
            </button>
            <div v-if="showSearchBox" class="search-box">
              <div class="search-box-header">
                <input
                  type="text"
                  v-model="searchQuery"
                  class="search-input"
                  placeholder="搜索页面内容..."
                  @keydown.enter.exact="nextMatch"
                  @keydown.shift.enter="prevMatch"
                />
                <div class="search-controls">
                  <div class="search-info" v-if="searchQuery.trim()">
                    <span>{{ currentMatchIndex + 1 }} / {{ totalMatches }}</span>
                  </div>
                  <button
                    class="search-nav-btn"
                    @click="prevMatch"
                    :disabled="totalMatches === 0"
                    title="上一个 (Shift+Enter)"
                  >
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      width="16"
                      height="16"
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                    >
                      <path d="M18 15l-6-6-6 6" />
                    </svg>
                  </button>
                  <button
                    class="search-nav-btn"
                    @click="nextMatch"
                    :disabled="totalMatches === 0"
                    title="下一个 (Enter)"
                  >
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      width="16"
                      height="16"
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                    >
                      <path d="M6 9l6 6 6-6" />
                    </svg>
                  </button>
                  <button
                    class="search-close-btn"
                    @click="handleSearch"
                    title="关闭 (ESC)"
                  >
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      width="16"
                      height="16"
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                    >
                      <line x1="18" y1="6" x2="6" y2="18" />
                      <line x1="6" y1="6" x2="18" y2="18" />
                    </svg>
                  </button>
                </div>
              </div>
            </div>
          </div>

          <div class="admin-info">
            <div class="admin-avatar">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                width="20"
                height="20"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
              >
                <path
                  d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"
                />
                <circle cx="12" cy="7" r="4" />
              </svg>
            </div>
            <span class="admin-name">管理员</span>
          </div>
        </div>
      </div>
    </header>

    <div class="layout-body">
      <!-- 侧边栏 -->
      <aside class="sidebar">
        <div class="sidebar-inner">
          <div class="sidebar-section-title">控制中心</div>

          <ul class="menu-list">
            <li
              v-for="item in menuItems"
              :key="item.key"
              class="menu-item"
            >
              <!-- 无子菜单：普通导航项 -->
              <button
                v-if="!item.children"
                :class="[
                  'nav-btn',
                  'nav-btn-main',
                  { active: activeKey === item.key }
                ]"
                @click="handleNavigation(item.key)"
              >
                <span class="nav-label">{{ item.label }}</span>
              </button>

              <!-- 有子菜单：分组标题 + 子项 -->
              <div v-else class="menu-group">
                <div class="menu-group-header">
                  <span class="menu-group-title">{{ item.label }}</span>
                </div>
                <ul class="submenu">
                  <li
                    v-for="child in item.children"
                    :key="child.key"
                    class="submenu-item"
                  >
                    <button
                      :class="[
                        'nav-btn',
                        'submenu-btn',
                        { active: activeKey === child.key }
                      ]"
                      @click="handleNavigation(child.key)"
                    >
                      <span class="submenu-dot" />
                      <span class="nav-label">{{ child.label }}</span>
                    </button>
                  </li>
                </ul>
              </div>
            </li>
          </ul>
        </div>
      </aside>

      <!-- 主内容区域 -->
      <main class="content">
        <div class="page-content">
          <slot></slot>
        </div>
      </main>
    </div>
  </div>
</template>

<style scoped>
.app-layout {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: #f4f6fb;
}

/* 顶部系统栏 */
.system-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 56px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  box-shadow: 0 2px 8px rgba(102, 126, 234, 0.2);
  z-index: 100;
  display: flex;
  align-items: center;
}

.system-header-content {
  width: 100%;
  padding: 0 24px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.system-name {
  font-size: 18px;
  font-weight: 700;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.system-header-right {
  display: flex;
  align-items: center;
  gap: 16px;
}

.header-icon-btn {
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.15);
  border: none;
  border-radius: 10px;
  color: white;
  cursor: pointer;
  transition: all 0.2s ease;
  padding: 0;
}

.header-icon-btn:hover {
  background: rgba(255, 255, 255, 0.22);
  transform: translateY(-1px);
}

.header-icon-btn:active {
  transform: translateY(0);
}

.header-icon-btn.active {
  background: rgba(255, 255, 255, 0.3);
}

/* 搜索容器 */
.search-container {
  position: relative;
}

/* 搜索框 */
.search-box {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 400px;
  max-width: min(400px, calc(100vw - 48px));
  background: white;
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(15, 35, 95, 0.2);
  z-index: 1000;
  padding: 12px;
  box-sizing: border-box;
}

.search-box-header {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}

.search-input {
  width: 100%;
  padding: 8px 12px;
  border: 2px solid #e5e7eb;
  border-radius: 8px;
  font-size: 14px;
  outline: none;
  transition: border-color 0.2s;
  box-sizing: border-box;
}

.search-input:focus {
  border-color: #667eea;
}

.search-controls {
  display: flex;
  align-items: center;
  gap: 8px;
}

.search-info {
  flex: 1;
  font-size: 12px;
  color: #6b7280;
  text-align: left;
}

.search-nav-btn,
.search-close-btn {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f3f4f6;
  border: none;
  border-radius: 6px;
  color: #374151;
  cursor: pointer;
  transition: all 0.2s;
  padding: 0;
}

.search-nav-btn:hover:not(:disabled) {
  background: #e5e7eb;
  color: #1f2937;
}

.search-nav-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.search-close-btn:hover {
  background: #fee2e2;
  color: #dc2626;
}

.admin-info {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 999px;
  cursor: pointer;
  transition: all 0.2s ease;
}

.admin-info:hover {
  background: rgba(255, 255, 255, 0.26);
}

.admin-avatar {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.25);
  border-radius: 50%;
  color: white;
}

.admin-name {
  font-size: 14px;
  font-weight: 500;
}

/* 主体区域布局 */
.layout-body {
  margin-top: 56px;
  display: flex;
  flex: 1;
  min-height: calc(100vh - 56px);
}

/* 侧边栏 */
.sidebar {
  position: fixed;
  top: 56px;
  bottom: 0;
  left: 0;
  width: 210px;
  background: #fbfbff;
  border-right: 1px solid #e5e7f5;
  box-shadow: 4px 0 18px rgba(23, 38, 83, 0.05);
  z-index: 20;
}

.sidebar-inner {
  padding: 18px 14px 16px;
  height: 100%;
  overflow-y: auto;
}

.sidebar-section-title {
  font-size: 13px;
  font-weight: 600;
  color: #9ca3af;
  letter-spacing: 0.08em;
  margin-bottom: 12px;
}

/* 菜单列表 */
.menu-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.menu-item + .menu-item {
  margin-top: 6px;
}

.nav-btn {
  width: 100%;
  border: none;
  outline: none;
  background: transparent;
  text-align: left;
  cursor: pointer;
  padding: 8px 12px 8px 18px;
  border-radius: 999px;
  font-size: 14px;
  color: #4b5563;
  display: flex;
  align-items: center;
  gap: 8px;
  position: relative;
  transition: all 0.18s ease;
}

.nav-btn-main {
  font-weight: 500;
}

.nav-btn:hover {
  background: rgba(129, 140, 248, 0.08);
  color: #4338ca;
}

/* 主项激活样式：淡紫渐变 + 左侧小圆点 */
.nav-btn-main.active {
  background: linear-gradient(
    90deg,
    rgba(129, 140, 248, 0.16) 0%,
    rgba(255, 255, 255, 0.96) 70%
  );
  color: #4338ca;
  box-shadow: 0 4px 12px rgba(129, 140, 248, 0.25);
}

.nav-btn-main.active::before {
  content: '';
  position: absolute;
  left: 8px;
  top: 50%;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: #4f46e5;
  transform: translateY(-50%);
}

/* 分组（攻击资源测绘） */
.menu-group {
  margin-top: 2px;
}

.menu-group-header {
  padding: 6px 4px 4px;
}

.menu-group-title {
  font-size: 13px;
  font-weight: 600;
  color: #6b7280;
}

/* 子菜单 */
.submenu {
  list-style: none;
  margin: 4px 0 2px;
  padding-left: 14px;
  border-left: 2px solid #e5e7f5;
}

.submenu-item + .submenu-item {
  margin-top: 4px;
}

.submenu-btn {
  padding-left: 18px;
  font-size: 13px;
  color: #6b7280;
}

.submenu-btn .nav-label {
  font-weight: 400;
}

.submenu-btn .submenu-dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: #c7d2fe;
  flex-shrink: 0;
}

.submenu-btn:hover {
  background: rgba(129, 140, 248, 0.08);
  color: #4338ca;
}

.submenu-btn:hover .submenu-dot {
  background: #818cf8;
}

/* 子项激活：同样淡紫胶囊 + 深色小圆点 */
.submenu-btn.active {
  background: linear-gradient(
    90deg,
    rgba(129, 140, 248, 0.18) 0%,
    rgba(255, 255, 255, 0.98) 70%
  );
  color: #4338ca;
  box-shadow: 0 4px 12px rgba(129, 140, 248, 0.3);
}

.submenu-btn.active .submenu-dot {
  background: #4f46e5;
}

/* 主内容区域 */
.content {
  flex: 1;
  margin-left: 210px;
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - 56px);
  width: calc(100% - 210px);
}

/* 页面内容容器：给右侧卡片一点留白 */
.page-content {
  flex: 1;
  padding: 18px 20px;
  overflow: auto;
}

/* 搜索高亮样式 */
:deep(.search-highlight) {
  background: #fef08a;
  color: #1f2937;
  padding: 2px 0;
  border-radius: 2px;
  font-weight: 500;
}

:deep(.search-highlight.current-match) {
  background: #fbbf24;
  color: #1f2937;
  box-shadow: 0 0 0 2px rgba(251, 191, 36, 0.3);
}

/* 响应式 */
@media (max-width: 768px) {
  .system-header-content {
    padding: 0 16px;
  }

  .system-name {
    font-size: 16px;
  }

  .sidebar {
    width: 180px;
  }

  .content {
    margin-left: 180px;
    width: calc(100% - 180px);
  }

  .page-content {
    padding: 12px 14px;
  }

  .admin-name {
    display: none;
  }

  .search-box {
    width: calc(100vw - 32px);
    right: -16px;
  }
}
</style>